from PIL import Image
import StringIO
from settings import MEDIA_ROOT
import os
from django.db import models
import imghdr
import Image

class ChunksImageField( models.ImageField ):	
	def pre_save( self, model_instance, add ):
		file = super( models.FileField, self ).pre_save(model_instance, add)
		if file and not file._committed:
			if callable( self.upload_to ):
				path = self.upload_to( model_instance, "" )
			else:
				path = self.upload_to
			file.name = path
			full_path = os.path.join( MEDIA_ROOT, path )
			chunks = _get_chunks( file.chunks() )
			self._save_image_func( model_instance, chunks, full_path )

		return file

class FixedImageField( ChunksImageField ):
	def __init__( self, max_size = 400, *args, **kwargs ):
		super( FixedImageField, self ).__init__( *args, **kwargs )
		self._max_size = max_size
	
	def _save_image_func( self, model_instance, chunks, path ):
		save_fixed_resolution_image( chunks, path, self._max_size )

class FixedThumbnailField( FixedImageField ):
	def _save_image_func( self, model_instance, chunks, path ):
		save_initial_thumbnail_image( chunks, path, self._max_size )

class Thumbnail( object ):
	def __init__( self, name, x_start, y_start, size ):
		self.name = name
		self.x_start = x_start
		self.y_start = y_start
		self.size = size		
	def as_str( self ):
		return "{0};{1};{2};{3}".format( self.name, self.x_start, self.y_start, self.size )

class ThumbnailField( models.Field ):
	# thumbnail is always linked to source image field

	_max_len = 40
	__metaclass__ = models.SubfieldBase

	def __init__( self, *args, **kwargs ):
		kwargs[ 'max_length' ] = self._max_len
		super( ThumbnailField, self ).__init__( *args, **kwargs )

	def db_type( self, connection ):
		return "varchar({0})".format( self._max_len )

	def get_prep_value( self, value ):
		# before send value to database

		if isinstance( value, unicode ):
			result = value
		else:
			if value != None:
				result = value.as_str()
			else:
				result = None
		return result

	def to_python( self, value ):		
		if isinstance( value, Thumbnail ):
			result = value
		else:
			if value != None:
				result = Thumbnail( *value.split( ";" ) )
			else:
				result = None
		return result

def _get_chunks( chunks ):
	chunks_ = ""
	for chunk in chunks:
		chunks_ += chunk
	return chunks_

def get_image( chunks ):
	chunks_ = ""
	for chunk in chunks:
		chunks_ += chunk

	virt_file = StringIO.StringIO( chunks_ )
	image = Image.open( virt_file )
	return image

def _calc_cropping( image ):
	dx = image.size[ 0 ] 
	dy = image.size[ 1 ]
	
	if dx > dy:
		x_start = ( dx - dy ) / 2
		y_start = 0
		offset = dy
	else:
		x_start = 0
		y_start = ( dy - dx ) / 2
		offset = dx

	return x_start, y_start, offset		

def _save_initial_thumbnail( image, size, out_file_path ):
	x_start, y_start, offset = _calc_cropping( image )
	image = _quad_crop_resize_to_thumbnail( image, x_start, y_start, offset, size )
	save_image( image, out_file_path )
	return ( x_start, y_start, offset, )	

def _init_thumbnail( src_image_name, size, name ):
	image = Image.open( os.path.join( MEDIA_ROOT, src_image_name ) )
	return [ name ] + list( _save_initial_thumbnail( image, size, os.path.join( MEDIA_ROOT, name ) ) )

image_max_size = 400
size_thumbnail = 260
size_small_thumbnail = 32

def init_thumbnail( src_image_name ):	
	from utils import get_thumbnail_path
	result = Thumbnail( *_init_thumbnail( src_image_name, size_thumbnail, get_thumbnail_path( src_image_name ) ) )
	return result

def init_small_thumbnail( src_image_name ):
	from lads.utils import get_small_thumbnail_path
	_init_thumbnail( src_image_name, size_small_thumbnail, get_small_thumbnail_path( src_image_name ) )

def save_initial_thumbnail_image( chunks, out_file_path, max_size ):
	image = get_image( chunks )
	_save_initial_thumbnail( image, max_size, out_file_path )

def save_fixed_resolution_image( chunks, out_file_path, max_size ):
	image = get_image( chunks )

	if image.size[ 0 ] > max_size or image.size[ 1 ] > max_size:
		image.thumbnail( ( image_max_size, max_size, ) )

	save_image( image, out_file_path )
	

def save_image( image, out_file_path ):
	image2 = Image.new( "RGBA", image.size )
	image2.paste( image )
	image2.save( out_file_path, "JPEG", quality = 100 )

def _quad_crop_resize_to_thumbnail( image, x, y, offset, thumbnail_size ):
	image = image.crop( ( x, y, x + offset, y + offset, ) )
	image = image.resize( ( thumbnail_size, thumbnail_size, ), Image.ANTIALIAS )	
	return image

def _update_thumbnail( src_image_name, out_image_name, x, y, offset, thumbnail_size ):
	from utils import while_path_exists
	src_image_dir = os.path.dirname( src_image_name )
	src_path = os.path.join( MEDIA_ROOT, src_image_name )
		
	im = Image.open( src_path )
	im = _quad_crop_resize_to_thumbnail( im, x, y, offset, thumbnail_size )
	out_image_dir = os.path.dirname( out_image_name )
	final_out_image_name = while_path_exists( os.path.join( MEDIA_ROOT, out_image_name ) )
	save_image( im, os.path.join( MEDIA_ROOT, out_image_dir, final_out_image_name ) )
	return final_out_image_name

def update_thumbnail( src_image_name, x, y, offset ):
	from utils import get_thumbnail_path
	return _update_thumbnail( src_image_name, get_thumbnail_path( src_image_name ), x, y, offset, size_thumbnail )
	
def update_small_thumbnail( src_image_name, x, y, offset ):
	from utils import get_small_thumbnail_path
	return _update_thumbnail( src_image_name, get_small_thumbnail_path( src_image_name ), x, y, offset, size_small_thumbnail )

def quad_crop_resize_file( src_file_path, out_file_path, x, y, size ):
	image = Image.open( src_file_path )
	image = quad_crop_resize_image( image, x, y, size )
	save_image( image, out_file_path )